use std::{env, fs, path::PathBuf, process::exit, time::Duration};

use log::LevelFilter;
use log4rs::{append::console::ConsoleAppender, encode::pattern::PatternEncoder};

mod client;
mod cmd;
mod config;
mod data;
mod file;
mod guard;
mod leader;
mod prelude;
mod ps;
mod robot;
mod router;
mod server;
mod session;
mod ws;

// https://github.com/actix/examples/blob/master/websockets/chat/src/main.rs
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    
    if env::var("AYISHA_HOME").is_err() {
        env::set_var("AYISHA_HOME", env::current_dir().unwrap());
    }

    if let Some(cmd) = config::get_cli_command() {
        match cmd {
            config::Commands::Server {
                config_file: _,
                log4rs_file,
                server_id: _,
                server_port: _,
                registry_file: _,
                hba_ident_file: _,
                pid_file: _,
            } => {
                if let Some(log4rs_file) = log4rs_file {
                    if !log4rs_file.exists() {
                        // 文件不存在
                        panic!("--log4rs-file: {}: No such file", log4rs_file.display());
                    }
                    log4rs::init_file(&log4rs_file, Default::default()).unwrap();
                }
                // 如果日志文件存在，则进行切换
                
            }

            config::Commands::Status { pid_file } => {
                let pid_file = pid_file.unwrap_or(PathBuf::from(config::DEFAULT_PID_FILE));
                if !pid_file.exists() {
                    // 文件不存在，不运行
                    eprintln!("{} not running", env!("CARGO_PKG_NAME"));
                    exit(1);
                }

                // 文件存在
                // 判断进程是否存在
                let mut i_pid = None;
                let pid_exists: bool = match fs::read_to_string(&pid_file) {
                    Ok(cont) => {
                        if let Ok(pid) = cont.parse::<usize>() {
                            i_pid = Some(pid);
                            ps::pid_exists(pid)
                        } else {
                            false
                        }
                    }
                    Err(_e) => false,
                };

                if !pid_exists {
                    eprintln!("{} not running", env!("CARGO_PKG_NAME"));
                    exit(1);
                }

                // 文件上次修改时间超过10秒，则说明程序hang住
                if let Ok(metadata) = pid_file.metadata() {
                    if let Ok(m) = metadata.modified() {
                        if m.elapsed().unwrap() >= Duration::from_secs(10) {
                            eprintln!(
                                "{} is hang, pid={:?}, last_modified={:?}",
                                env!("CARGO_PKG_NAME"),
                                i_pid,
                                m.elapsed()
                            );
                            exit(2);
                        }
                    }
                }

                println!("{} is running", env!("CARGO_PKG_NAME"));

                exit(0);
            }

            config::Commands::Shutdown {
                registry_file,
                pid_file,
            } => {
                let stdout = ConsoleAppender::builder()
                    .encoder(Box::new(PatternEncoder::new("[{l}] {m}{n}")))
                    .build();
                let config = log4rs::Config::builder()
                    .appender(log4rs::config::Appender::builder().build("stdout", Box::new(stdout)))
                    .build(
                        log4rs::config::Root::builder()
                            .appender("stdout")
                            .build(LevelFilter::Info),
                    )
                    .unwrap();
                let _ = log4rs::init_config(config).unwrap();

                let pid_file = pid_file.unwrap_or(PathBuf::from(config::DEFAULT_PID_FILE));
                if !pid_file.exists() {
                    // 文件不存在，不运行
                    eprintln!("{} not running", env!("CARGO_PKG_NAME"));
                    exit(1);
                }

                // 文件存在
                // 判断进程是否存在
                match fs::read_to_string(&pid_file) {
                    Ok(cont) => {
                        if let Ok(pid) = cont.parse::<usize>() {
                            ps::kill(pid, false);
                            // if ps::pid_exists(pid) {
                            //     eprintln!("{} process shutdown failed", env!("CARGO_PKG_NAME"));
                            //     exit(1);
                            // }
                        }
                    }
                    Err(_e) => {}
                };

                // 需要把其他关联服务也停止
                if let Some(registry_file) = registry_file {
                    let c = config::get_raw_registry(registry_file);
                    let mut err_count = 0;
                    for (srv_name, rse) in c.services {
                        println!("Stop registry service {srv_name}");
                        match cmd::run_stop_cmd(&srv_name, rse) {
                            Some((_o, e)) => {
                                if e.len() > 0 {
                                    err_count += 1;
                                }
                            },
                            None => continue,
                        }
                    }
                    if err_count > 0 {
                        exit(1);
                    }
                }

                exit(0);
            }

            config::Commands::Version {} => {
                // https://doc.rust-lang.org/cargo/reference/environment-variables.html
                let head_version = match option_env!("HEAD_VERSION") {
                    Some(k) => {
                        let (first, _last) = k.split_at(7);
                        format!(", build {}", first)
                    }
                    None => String::new(),
                };

                let build_time = match option_env!("BUILD_TIME") {
                    Some(k) => format!(" on {}", k),
                    None => String::new(),
                };

                println!(
                    "{} {}.{}.{}{}{}{} {}/{}",
                    env!("CARGO_PKG_NAME"),
                    env!("CARGO_PKG_VERSION_MAJOR"),
                    env!("CARGO_PKG_VERSION_MINOR"),
                    env!("CARGO_PKG_VERSION_PATCH"),
                    option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""),
                    head_version,
                    build_time,
                    env::consts::OS,
                    env::consts::ARCH,
                );
                exit(0);
            }
        }
    }

    prelude::print();

    let _registry = config::get_registry();

    // use rsa::{RsaPrivateKey, RsaPublicKey};
    // let mut rng = rand::thread_rng();
    // let bits = 2048;
    // let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
    // let pub_key = RsaPublicKey::from(&priv_key);
    // let a = priv_key.to_pkcs1_pem(rsa::pkcs8::LineEnding::LF).and_then(| a | {
    //     pub_key.to_pkcs1_pem(rsa::pkcs8::LineEnding::LF)
    // });
    // println!("priv_key::{:?}", priv_key.to_pkcs1_pem(rsa::pkcs8::LineEnding::LF).unwrap());
    // println!("pub_key::{:?}", pub_key.to_pkcs1_pem(rsa::pkcs8::LineEnding::LF).unwrap().as_bytes().len());

    let _ = robot::start().await;

    // println!("OK.");

    Ok(())
}
